﻿using ServiceStack.Script;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

namespace ERefCommon
{
    /// <summary>
    /// json工具类
    /// </summary>
    public static class JsonTool
    {
        /// <summary>
        /// 根据json的结点路径获取结点值
        /// </summary>
        /// <param name="jsonFilePath">json文件路径</param>
        /// <param name="tokenPath">json结点路径</param>
        /// <returns>json结点值字符串</returns>
        /// <exception cref="ArgumentNullException">参数为空异常</exception>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        public static string GetJsonStr(string jsonFilePath, string tokenPath)
        {
            ValidPms(jsonFilePath, tokenPath);
            FmtFilePathAndExistCheck(ref jsonFilePath);
            string sourceStr = File.ReadAllText(jsonFilePath);
            string[] targetPathArray = tokenPath.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            if (targetPathArray == null || targetPathArray.Length <= 0)
            {
                throw new ArgumentException("json结点路径解析错误");
            }
            JsonNode? tmpNode=JsonNode.Parse(sourceStr);
            for (int i = 0; i < targetPathArray.Length; i++) 
            {
                if (tmpNode == null) 
                {
                    return string.Empty;
                }
                tmpNode = tmpNode[targetPathArray[i]];
            }
            if (tmpNode == null)
            {
                return string.Empty;
            }            
            return tmpNode.GetValue<string>();
            //return tmpNode.ToJsonString(new JsonSerializerOptions() { 
            //    PropertyNameCaseInsensitive = true,
            //    DefaultIgnoreCondition=JsonIgnoreCondition.Never,
            //    Converters = {
            //        new JsonDateTimeConverter()
            //    }
            //});
        }
        /// <summary>
        /// 根据json的结点路径设置结点值
        /// </summary>
        /// <param name="jsonFilePath">json文件路径</param>
        /// <param name="tokenPath">json结点路径</param>
        /// <param name="tokenValue">json结点值字符串</param>
        /// <exception cref="ArgumentNullException">参数为空异常</exception>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        /// <exception cref="ArgumentException">变量错误异常</exception>
        public static void SetJsonStr(string jsonFilePath, string tokenPath, string tokenValue)
        {
            ValidPms(jsonFilePath, tokenPath);
            FmtFilePathAndExistCheck(ref jsonFilePath);
            string sourceStr = File.ReadAllText(jsonFilePath);
            string[] targetPathArray = tokenPath.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            if (targetPathArray == null || targetPathArray.Length <= 0)
            {
                throw new ArgumentException("json结点路径解析错误");
            }
            JsonNode? tmpNode = JsonNode.Parse(sourceStr);
            for (int i = 0; i < targetPathArray.Length-1; i++)
            {
                if (tmpNode == null)
                {
                    return;
                }
                tmpNode = tmpNode[targetPathArray[i]];
            }
            if (tmpNode == null)
            {
                return;
            }
            tmpNode[targetPathArray.Length - 1] = JsonValue.Create(tokenValue);
            tmpNode = tmpNode.Parent;
            string? jsonText= tmpNode?.ToJsonString(new JsonSerializerOptions() {
                PropertyNameCaseInsensitive = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                Converters = {
                    new JsonDateTimeConverter()
                }
            });
            if (!string.IsNullOrWhiteSpace(jsonText))
            {
                return;
            }
            lock ("JsonTool") 
            {
                File.WriteAllText(jsonFilePath, jsonText); 
            }
        }

        /// <summary>
        /// 对象序列化为json字符串，时间格式为国际标准，空值显示
        /// </summary>
        /// <param name="obj">要序列化的对象</param>
        /// <returns>json字符串</returns>
        public static string ToJson(object obj)
        {
            return JsonSerializer.Serialize(obj, obj.GetType(), new JsonSerializerOptions()
            {
                PropertyNameCaseInsensitive = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                Converters = {
                    new JsonDateTimeConverter()
                }
            });
        }

        /// <summary>
        /// json字符串反序列化为泛型
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <returns>泛型结果</returns>
        public static T? ToGeneric<T>(string json)
        {
            return JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions()
            {
                PropertyNameCaseInsensitive = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                Converters = {
                    new JsonDateTimeConverter()
                }
            });
        }

        /// <summary>
        /// json字符串反序列化为泛型集合类，单一实体会自动转换为集合
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <returns>泛型集合结果</returns>
        public static List<T>? ToGenericList<T>(string json)
        {
            JsonNode? tmpNode = JsonNode.Parse(json);
            if (tmpNode == null) { return null; }
            List<T>? resList = new List<T>();
            if (tmpNode is JsonArray)
            {
                resList = JsonSerializer.Deserialize<List<T>>(json, new JsonSerializerOptions()
                {
                    PropertyNameCaseInsensitive = true,
                    DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                    Converters = {
                    new JsonDateTimeConverter()
                }
                });
            }
            else
            {
                T? item = JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions()
                {
                    PropertyNameCaseInsensitive = true,
                    DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                    Converters = {
                    new JsonDateTimeConverter()
                }
                });
                if (item != null) 
                {
                    resList.Add(item);
                }
                
            }
            if (resList == null || resList.Count <= 0) 
            {
                return null;
            }
            return resList;
        }

        /// <summary>
        /// json字符串反序列化为对象
        /// </summary>
        /// <param name="json">json字符串</param>
        /// <returns>对象结果</returns>
        public static object? ToObj(string json)
        {
            return JsonSerializer.Deserialize<object>(json, new JsonSerializerOptions()
            {
                PropertyNameCaseInsensitive = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                Converters = {
                    new JsonDateTimeConverter()
                }
            });
        }


        /// <summary>
        /// 验证参数
        /// </summary>
        /// <param name="jsonFilePath">json文件路径</param>
        /// <param name="tokenPath">json配置路径</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">变量为空异常</exception>
        private static void ValidPms(string jsonFilePath, string tokenPath)
        {
            if (jsonFilePath == null || string.IsNullOrEmpty(jsonFilePath))
            {
                throw new ArgumentNullException("jsonFilePath", "json文件路径不存在");
            }
            if (tokenPath == null || string.IsNullOrEmpty(tokenPath))
            {
                throw new ArgumentNullException("tokenPath", "json结点路径为空");
            }            
        }

        /// <summary>
        /// 处理文件路径为全平台兼容模式，并验证文件是否存在
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <exception cref="FileNotFoundException">文件不存在异常</exception>
        private static void FmtFilePathAndExistCheck(ref string filePath)
        {
            filePath = filePath.Replace('\\', Path.DirectorySeparatorChar);
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("文件不存在", filePath);
            }
        }
    }
}
